Animal movement visualization

For our project, we wanted to test different methods and packages to visualize animal movement data. Specifically, we wanted to figure out the best way to create maps and plots to display GPS data.

Two Australian Invasive Lethal Species (TAILS)

We wanted to utilize data that was collected and uploaded to Movebank to familiarize ourselves with that platform. We found a unique data set of GPS collared feral cats and European foxes in Australia. These mammals are both invasive to the area. We wanted to communicate their movement patterns and home range sizes in a comparative framework without statistical analyses.

Home ranges

Although we wanted to largely stya away from satistics, some tools are a useful way to visualize differenes in the boundaries of areas being used by individuals. Here, we created minimum convex polygons (MCP) and kernel density estimators (KDE) for three cats and three foxes from August through November in 2017. We wanted to also see if the size of the area the individuals used differed.

Visualization 1a: Home ranges: Cats

# Creating home ranges for cats

# Read in libraries ----
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.1.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(amt)
## Warning: package 'amt' was built under R version 4.1.3
## 
## Attaching package: 'amt'
## The following object is masked from 'package:stats':
## 
##     filter
# Read in data ----
# Cat GPS data and reference data
x <- read.csv("Data/Feral cat (Felis catus) - Scotia, NSW-reference-data.csv")
cat <- read.csv("Data/Feral cat (Felis catus) - Scotia, NSW.csv")

# Prepare the data ----
# Filter individuals in 2017 with greater than 600 data pints
cat_choice <- cat %>% 
  filter(year(timestamp) %in% 2017) %>% 
  group_by(individual.local.identifier) %>% 
  summarise(n = length(location.long)) %>% 
  filter(n >= 600) 
  
# Filter individuals in reference file to see metadata
cat_check <- x %>% 
  filter(animal.id %in% cat_choice$individual.local.identifier) 

# visualize in table the cats per year
table(x$animal.id, x$animal.sex, year(x$deploy.on.date))  
## , ,  = 2016
## 
##            
##             f m
##   Arj_MC274 0 0
##   Bec_FC232 0 0
##   Ben_MC236 0 0
##   Col_MC265 0 0
##   Con_MC266 0 1
##   Fay_FC321 0 0
##   Ivy_FC489 0 0
##   Jed_MC533 0 1
##   Jon_MC566 0 1
##   Kay_FC329 0 0
##   Ken_MC536 0 1
##   Leo_MC536 0 0
##   Lyn_FC596 0 0
##   Max_MC629 0 0
##   Mia_FC642 0 0
##   Pam_FC726 0 0
##   Ray_MC729 0 0
##   Roy_MC769 0 0
##   Syd_MC793 0 0
##   Ted_MC833 0 0
##   Tex_MC839 0 0
##   Vic_MC842 0 0
##   Wal_MC925 0 0
##   Wes_MC937 0 1
##   Zac_MC922 0 0
## 
## , ,  = 2017
## 
##            
##             f m
##   Arj_MC274 0 0
##   Bec_FC232 0 0
##   Ben_MC236 0 1
##   Col_MC265 0 0
##   Con_MC266 0 0
##   Fay_FC321 0 0
##   Ivy_FC489 1 0
##   Jed_MC533 0 0
##   Jon_MC566 0 0
##   Kay_FC329 1 0
##   Ken_MC536 0 1
##   Leo_MC536 0 0
##   Lyn_FC596 0 0
##   Max_MC629 0 1
##   Mia_FC642 1 0
##   Pam_FC726 0 0
##   Ray_MC729 0 1
##   Roy_MC769 0 1
##   Syd_MC793 0 1
##   Ted_MC833 0 0
##   Tex_MC839 0 1
##   Vic_MC842 0 0
##   Wal_MC925 0 0
##   Wes_MC937 0 0
##   Zac_MC922 0 0
## 
## , ,  = 2018
## 
##            
##             f m
##   Arj_MC274 0 1
##   Bec_FC232 1 0
##   Ben_MC236 0 0
##   Col_MC265 0 1
##   Con_MC266 0 0
##   Fay_FC321 1 0
##   Ivy_FC489 1 0
##   Jed_MC533 0 0
##   Jon_MC566 0 0
##   Kay_FC329 0 0
##   Ken_MC536 0 1
##   Leo_MC536 0 1
##   Lyn_FC596 1 0
##   Max_MC629 0 0
##   Mia_FC642 0 0
##   Pam_FC726 1 0
##   Ray_MC729 0 0
##   Roy_MC769 0 1
##   Syd_MC793 0 0
##   Ted_MC833 0 1
##   Tex_MC839 0 0
##   Vic_MC842 0 1
##   Wal_MC925 0 1
##   Wes_MC937 0 0
##   Zac_MC922 0 1
# Grab sex from reference data
sex <- x %>% 
  select(animal.id,
         animal.sex)

# Okay, not lets do some renaming
cat_choice <- cat %>% 
  filter(year(timestamp) %in% 2017) %>% 
  # select cols and rename
  select(animal.id = individual.local.identifier,
         y = location.lat,
         x = location.long,
         utm.y = utm.easting,
         utm.x = utm.northing,
         utm.zone,
         dt = timestamp) %>% 
  # join with ref data
  left_join(sex, by = "animal.id") %>% 
  # rename again
  rename(sex = animal.sex,
         id = animal.id) %>% 
  # filter time
  filter(hour(dt) %in% c(0, 6, 12, 18),
         month(dt) %in% 8:11) %>% 
  # change class of col
  mutate(x = as.numeric(x),
         y = as.numeric(y),
         dt = as.Date(dt)) %>% 
  # arrange asc date and time
  arrange(dt)


# Home range analysis:
# Make track for hr analysis
cat_track <- mk_track(tbl = cat_choice, .x = x, .y = y, .t = dt, 
                      id = id, crs = 23884)


# create hrs per cat
cat <- unique(cat_choice$id)
cat_mcp <- list()
cat_kde <- list()

# loop
for(i in 1:length(cat)){
  x <- cat_track %>% 
    filter(id == cat[i]) 
  
    cat_mcp[[i]] <- hr_mcp(x = x, 
                    levels = c(0.95, 0.5), 
                    keep.data = TRUE)
    
    # Fit KDE
    cat_kde[[i]] <- hr_kde(x = x,
                       levels = c(0.95, 0.5),
                       keep.data = TRUE,
                       h = hr_kde_ref(x), #default
                       trast = make_trast(x))
    

}

# name the list elements
names(cat_kde) <- names(cat_mcp) <- cat

# plot: minimum convex Polygon for 3 cats August - November 2017
plot(cat_mcp[[1]], main = "MCP: Ben", col = "coral")

plot(cat_mcp[[2]], main = "MCP: Ivy", col = "lightblue")

plot(cat_mcp[[3]], main = "MCP: Ken", col = "darkolivegreen3")

# plot: Kernel density Estimates for 3 cats August - November 2017
plot(cat_kde[[1]], main = "KDE: Ben", col = "coral")

plot(cat_kde[[2]], main = "KDE: Ivy", col = "lightblue")

plot(cat_kde[[3]], main = "KDE: Ken", col = "darkolivegreen3")

# To extract the areas from all MCPs
mcp_areas <- lapply(cat_mcp, hr_area)
kde_areas <- lapply(cat_kde, hr_area)

c_kde_df <- bind_rows(kde_areas, .id = "id")
c_mcp_df <- bind_rows(mcp_areas, .id = "id")

Visualization 1b: Home ranges: Foxes

##      tag.id animal.id  animal.taxon          deploy.on.date
## 1  151-2587       Moe Vulpes vulpes 2015-10-07 20:40:39.000
## 2  150-3603       Jim Vulpes vulpes 2015-10-13 22:00:38.000
## 3  151-2378       Liz Vulpes vulpes 2015-10-19 20:40:38.000
## 4  151-2983       Kim Vulpes vulpes 2015-11-08 20:00:37.000
## 5  150-3987       Mem Vulpes vulpes 2015-11-23 20:40:38.000
## 6  151-2779       Zoe Vulpes vulpes 2015-11-23 22:00:38.000
## 7  151-3384       Ann Vulpes vulpes 2015-11-30 14:00:37.000
## 8  151-3981       Bob Vulpes vulpes 2016-07-31 14:00:36.000
## 9  150-5573       Flo Vulpes vulpes 2016-07-31 14:00:36.000
## 10 150-3987       Reg Vulpes vulpes 2016-07-31 14:00:37.000
## 11 151-2378       Ada Vulpes vulpes 2016-07-31 14:00:37.000
## 12 150-3603       Zoe Vulpes vulpes 2016-07-31 14:00:37.000
## 13 151-1784       Oli Vulpes vulpes 2016-07-31 14:00:37.000
## 14 151-3384       Bea Vulpes vulpes 2016-07-31 14:00:39.000
## 15 151-2779       Cat Vulpes vulpes 2016-07-31 14:01:03.000
## 16 151-3197       Val Vulpes vulpes 2016-08-31 14:00:37.000
## 17 150-3803       Joy Vulpes vulpes 2016-08-31 14:00:38.000
## 18 151-3384       Flo Vulpes vulpes 2017-07-31 14:00:36.000
## 19 150-3603       Don Vulpes vulpes 2017-07-31 14:00:38.000
## 20 151-1784       Ern Vulpes vulpes 2017-07-31 14:00:39.000
## 21 151-2779       Joy Vulpes vulpes 2017-07-31 14:00:39.000
## 22 151-3586       Kev Vulpes vulpes 2017-07-31 14:00:39.000
## 23 151-2378       Ros Vulpes vulpes 2017-07-31 14:00:43.000
## 24 151-2216       Jen Vulpes vulpes 2017-07-31 14:00:44.000
## 25 150-5573       Oli Vulpes vulpes 2017-07-31 14:00:44.000
## 26 151-3197       Lou Vulpes vulpes 2017-07-31 14:01:05.000
##            deploy.off.date animal.mass animal.sex attachment.type
## 1  2016-02-02 03:30:44.000        4750          m          collar
## 2  2016-01-25 13:40:37.000        4000          m          collar
## 3  2016-02-11 12:00:36.000        4000          f          collar
## 4  2015-12-04 03:30:48.000        5000          f          collar
## 5  2016-01-25 13:40:38.000        3000          f          collar
## 6  2016-03-11 12:00:37.000        4000          f          collar
## 7  2016-03-11 12:00:36.000        4000          f          collar
## 8  2016-09-02 16:01:05.000        4750          m          collar
## 9  2016-11-24 12:20:37.000        4550          f          collar
## 10 2016-11-25 13:40:37.000        4400          m          collar
## 11 2016-11-14 02:12:46.000        3600          f          collar
## 12 2016-08-22 11:00:36.000        3650          f          collar
## 13 2016-11-24 13:00:38.000        4400          m          collar
## 14 2016-11-24 13:00:38.000        3600          f          collar
## 15 2016-08-21 18:20:38.000        4650          f          collar
## 16 2016-12-23 21:40:37.000        3600          f          collar
## 17 2016-12-22 13:20:38.000        3800          f          collar
## 18 2017-08-15 07:00:44.000        4400          f          collar
## 19 2017-11-21 10:40:36.000        5400          m          collar
## 20 2017-10-26 17:40:38.000        4600          m          collar
## 21 2017-10-26 18:20:37.000        3600          f          collar
## 22 2017-11-20 13:00:38.000        4300          m          collar
## 23 2017-10-26 16:00:37.000        4000          f          collar
## 24 2017-10-31 12:40:39.000        4100          f          collar
## 25 2017-10-31 13:20:38.000        4900          m          collar
## 26 2017-11-20 13:00:37.000        3200          m          collar
##    deploy.off.person deploy.on.person deployment.end.type deployment.id
## 1      Andrew Carter    Andrew Carter   equipment-failure  Moe_151-2587
## 2      Andrew Carter    Andrew Carter            fall-off  Jim_150-3603
## 3      Andrew Carter    Andrew Carter            fall-off  Liz_151-2378
## 4      Andrew Carter    Andrew Carter   equipment-failure  Kim_151-2983
## 5      Andrew Carter    Andrew Carter            fall-off  Mem_150-3987
## 6      Andrew Carter    Andrew Carter            fall-off  Zoe_151-2779
## 7      Andrew Carter    Andrew Carter            fall-off  Ann_151-3384
## 8      Andrew Carter    Andrew Carter                dead  Bob_151-3981
## 9      Andrew Carter    Andrew Carter            fall-off  Flo_150-5573
## 10     Andrew Carter    Andrew Carter                dead  Reg_150-3987
## 11     Andrew Carter    Andrew Carter                dead  Ada_151-2378
## 12     Andrew Carter    Andrew Carter                dead  Zoe_150-3603
## 13     Andrew Carter    Andrew Carter            fall-off  Oli_151-1784
## 14     Andrew Carter    Andrew Carter            fall-off  Bea_151-3384
## 15     Andrew Carter    Andrew Carter                dead  Cat_151-2779
## 16     Andrew Carter    Andrew Carter            fall-off  Val_151-3197
## 17     Andrew Carter    Andrew Carter            fall-off  Joy_150-3803
## 18     Andrew Carter    Andrew Carter                dead  Flo_151-3384
## 19     Andrew Carter    Andrew Carter            fall-off  Don_150-3603
## 20     Andrew Carter    Andrew Carter                dead  Ern_151-1784
## 21     Andrew Carter    Andrew Carter                dead  Joy_151-2779
## 22     Andrew Carter    Andrew Carter            fall-off  Kev_151-3586
## 23     Andrew Carter    Andrew Carter                dead  Ros_151-2378
## 24     Andrew Carter    Andrew Carter                dead  Jen_151-2216
## 25     Andrew Carter    Andrew Carter                dead  Oli_150-5573
## 26     Andrew Carter    Andrew Carter            fall-off  Lou_151-3197
##    manipulation.type tag.beacon.frequency                       tag.comments
## 1               none               151.26                         2015 = Moe
## 2               none               150.36 2015 = Jim; 2016 = Zoe; 2017 = Don
## 3               none               151.24 2015 = Liz; 2016 = Ada; 2017 = Ros
## 4               none               151.30                         2015 = Kim
## 5               none               150.40             2015 = Mem; 2016 = Reg
## 6               none               151.28 2015 = Zoe; 2016 = Cat; 2017 = Joy
## 7               none               151.34 2015 = Ann; 2016 = Bea; 2017 = Flo
## 8               none               151.40             2016 = Bob; 2017 = Ned
## 9               none               150.56             2016 = Flo; 2017 = Oli
## 10              none               150.40             2015 = Mem; 2016 = Reg
## 11              none               151.24 2015 = Liz; 2016 = Ada; 2017 = Ros
## 12              none               150.36 2015 = Jim; 2016 = Zoe; 2017 = Don
## 13              none               151.18             2016 = Oli; 2017 = Ern
## 14              none               151.34 2015 = Ann; 2016 = Bea; 2017 = Flo
## 15              none               151.28 2015 = Zoe; 2016 = Cat; 2017 = Joy
## 16              none               151.32             2016 = Val; 2017 = Lou
## 17              none               150.38             2016 = Joy; 2017 = Abe
## 18              none               151.34 2015 = Ann; 2016 = Bea; 2017 = Flo
## 19              none               150.36 2015 = Jim; 2016 = Zoe; 2017 = Don
## 20              none               151.18             2016 = Oli; 2017 = Ern
## 21              none               151.28 2015 = Zoe; 2016 = Cat; 2017 = Joy
## 22              none               151.36                         2017 = Kev
## 23              none               151.24 2015 = Liz; 2016 = Ada; 2017 = Ros
## 24              none               151.22                         2017 = Jen
## 25              none               150.56             2016 = Flo; 2017 = Oli
## 26              none               151.32             2016 = Val; 2017 = Lou
##                                                                                                               tag.failure.comments
## 1                                                                                     Remote drop-off failed. Collar not recovered
## 2                                                                                                                                 
## 3                                                                                                                                 
## 4                                                                                    Remote drop-off failed. Collar not retreived.
## 5  Last remote download attempt before programmed drop-off date failed.\n\nRemote drop off failed?collar recovered after Reg died.
## 6                                                                                                                                 
## 7                         in 2017, collar only collected fixes for ~17 days. Manufacturer suggested flat GPS battery likely cause.
## 8      In 2017, collared collected GPS fixes for 2 days then stopped. Manufacturer suggested GPS battery failure was likely cause.
## 9                                                                                                                                 
## 10 Last remote download attempt before programmed drop-off date failed.\n\nRemote drop off failed?collar recovered after Reg died.
## 11                                                                                                                                
## 12                                                                                                                                
## 13                                                                                                                                
## 14                        in 2017, collar only collected fixes for ~17 days. Manufacturer suggested flat GPS battery likely cause.
## 15                                                                                                                                
## 16                                                                                                                                
## 17                 Faulty VHF signal in 2017. Tag gave mortality signal when the fox was still alive (as confirmed visually by AC)
## 18                        in 2017, collar only collected fixes for ~17 days. Manufacturer suggested flat GPS battery likely cause.
## 19                                                                                                                                
## 20                                                                                                                                
## 21                                                                                                                                
## 22                                                                                                                                
## 23                                                                                                                                
## 24                                                                                                                                
## 25                                                                                                                                
## 26                                                                                                                                
##    tag.manufacturer.name tag.mass                                     tag.model
## 1    Telemetry Solutions      171 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 2    Telemetry Solutions      175 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 3    Telemetry Solutions      176 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 4    Telemetry Solutions      174 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 5    Telemetry Solutions      175 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 6    Telemetry Solutions      178 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 7    Telemetry Solutions      175 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 8    Telemetry Solutions       NA Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 9    Telemetry Solutions       NA Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 10   Telemetry Solutions      175 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 11   Telemetry Solutions      176 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 12   Telemetry Solutions      175 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 13   Telemetry Solutions       NA Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 14   Telemetry Solutions      175 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 15   Telemetry Solutions      178 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 16   Telemetry Solutions      174 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 17   Telemetry Solutions      178 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 18   Telemetry Solutions      175 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 19   Telemetry Solutions      175 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 20   Telemetry Solutions       NA Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 21   Telemetry Solutions      178 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 22   Telemetry Solutions       NA Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 23   Telemetry Solutions      176 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 24   Telemetry Solutions      177 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 25   Telemetry Solutions       NA Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
## 26   Telemetry Solutions      174 Quantum 4000 Enhanced Ext Acc LS26500 SIRFIII
##    tag.production.date tag.serial.no
## 1                 2015      17613615
## 2                 2015      17613115
## 3                 2015      17613515
## 4                 2015      17613815
## 5                 2015      17613315
## 6                 2015      17613715
## 7                 2015      17614015
## 8                 2016      37514616
## 9                 2016      37519716
## 10                2015      17613315
## 11                2015      17613515
## 12                2015      17613115
## 13                2016      37519816
## 14                2015      17614015
## 15                2015      17613715
## 16                2015      17613915
## 17                2015      17613215
## 18                2015      17614015
## 19                2015      17613115
## 20                2016      37519816
## 21                2015      17613715
## 22                2016      37514416
## 23                2015      17613515
## 24                2015      17613415
## 25                2016      37519716
## 26                2015      17613915
## , ,  = 2015
## 
##      
##       f m
##   Ada 0 0
##   Ann 1 0
##   Bea 0 0
##   Bob 0 0
##   Cat 0 0
##   Don 0 0
##   Ern 0 0
##   Flo 0 0
##   Jen 0 0
##   Jim 0 1
##   Joy 0 0
##   Kev 0 0
##   Kim 1 0
##   Liz 1 0
##   Lou 0 0
##   Mem 1 0
##   Moe 0 1
##   Oli 0 0
##   Reg 0 0
##   Ros 0 0
##   Val 0 0
##   Zoe 1 0
## 
## , ,  = 2016
## 
##      
##       f m
##   Ada 1 0
##   Ann 0 0
##   Bea 1 0
##   Bob 0 1
##   Cat 1 0
##   Don 0 0
##   Ern 0 0
##   Flo 1 0
##   Jen 0 0
##   Jim 0 0
##   Joy 1 0
##   Kev 0 0
##   Kim 0 0
##   Liz 0 0
##   Lou 0 0
##   Mem 0 0
##   Moe 0 0
##   Oli 0 1
##   Reg 0 1
##   Ros 0 0
##   Val 1 0
##   Zoe 1 0
## 
## , ,  = 2017
## 
##      
##       f m
##   Ada 0 0
##   Ann 0 0
##   Bea 0 0
##   Bob 0 0
##   Cat 0 0
##   Don 0 1
##   Ern 0 1
##   Flo 1 0
##   Jen 1 0
##   Jim 0 0
##   Joy 1 0
##   Kev 0 1
##   Kim 0 0
##   Liz 0 0
##   Lou 0 1
##   Mem 0 0
##   Moe 0 0
##   Oli 0 1
##   Reg 0 0
##   Ros 1 0
##   Val 0 0
##   Zoe 0 0

Home range area comparison

hist(c_mcp_df$area, main = "MCP: Cat home range area distribution", col = "lightgreen",
     xlab = "Area")

hist(c_kde_df$area, main = "KDE: Cat home range area distribution", col = "cyan",
     xlab = "Area")

hist(f_mcp_df$area, main = "MCP: Fox home range area distribution", col = "goldenrod",
     xlab = "Area")

hist(f_kde_df$area, main = "KDE: Fox home range area distribution", col = "pink",
     xlab = "Area")

##Movetrack visualization: cats Now that we can see static home ranges to visualize size and shape variance, we wanted to explore animating the GPS location points to trace the movements of individuals and plot them on a map. The package we used is called moveVis, which requires the data to be formatted as a “movestack” object.

library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.6     v purrr   0.3.4
## v tibble  3.1.6     v stringr 1.4.1
## v tidyr   1.2.0     v forcats 0.5.2
## v readr   2.1.2
## Warning: package 'ggplot2' was built under R version 4.1.3
## Warning: package 'tibble' was built under R version 4.1.3
## Warning: package 'tidyr' was built under R version 4.1.3
## Warning: package 'readr' was built under R version 4.1.3
## Warning: package 'stringr' was built under R version 4.1.3
## Warning: package 'forcats' was built under R version 4.1.3
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x lubridate::as.difftime() masks base::as.difftime()
## x lubridate::date()        masks base::date()
## x amt::filter()            masks dplyr::filter(), stats::filter()
## x lubridate::intersect()   masks base::intersect()
## x dplyr::lag()             masks stats::lag()
## x lubridate::setdiff()     masks base::setdiff()
## x lubridate::union()       masks base::union()
library(lubridate)
library(move)
## Warning: package 'move' was built under R version 4.1.3
## Loading required package: geosphere
## 
## Attaching package: 'geosphere'
## The following object is masked from 'package:amt':
## 
##     centroid
## Loading required package: sp
## 
## Attaching package: 'sp'
## The following object is masked from 'package:amt':
## 
##     bbox
## Loading required package: raster
## 
## Attaching package: 'raster'
## The following object is masked from 'package:amt':
## 
##     select
## The following object is masked from 'package:dplyr':
## 
##     select
## Loading required package: rgdal
## Warning: package 'rgdal' was built under R version 4.1.3
## Please note that rgdal will be retired by the end of 2023,
## plan transition to sf/stars/terra functions using GDAL and PROJ
## at your earliest convenience.
## 
## rgdal: version: 1.5-32, (SVN revision 1176)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 3.4.1, released 2021/12/27
## Path to GDAL shared files: C:/Users/veron/OneDrive - The Pennsylvania State University/Documents/R/win-library/4.1/rgdal/gdal
## GDAL binary built with GEOS: TRUE 
## Loaded PROJ runtime: Rel. 7.2.1, January 1st, 2021, [PJ_VERSION: 721]
## Path to PROJ shared files: C:\Program Files\PostgreSQL\13\share\contrib\postgis-3.0\proj
## PROJ CDN enabled: FALSE
## Linking to sp version:1.4-7
## To mute warnings of possible GDAL/OSR exportToProj4() degradation,
## use options("rgdal_show_exportToProj4_warnings"="none") before loading sp or rgdal.
## 
## Attaching package: 'move'
## The following object is masked from 'package:amt':
## 
##     speed
library(moveVis)
## Warning: package 'moveVis' was built under R version 4.1.3
## Find a collection of moveVis animations created by other users on
## Twitter: https://twitter.com/schwalbwillmann
library(RColorBrewer)
## Warning: package 'RColorBrewer' was built under R version 4.1.3
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.1.3
#load cat data from Movebank as Movestack
# create 'login'
loginStored <- movebankLogin(username="mbstum", password="Cq6j9m4KrQRQGJ@")
cats <- getMovebankData("Feral cat (Felis catus) - Scotia, NSW", login = loginStored, includeExtraSensors = TRUE)
# https://cran.r-project.org/web/packages/move/index.html

#subsetting cats dataset as a Movestack object
#visual data exploration to chose cats with the most gps fixes within a similar time period
#subset cats for only Aug - Nov 2017

#list of cats to use
cat_list <- c("Ben_MC236", "Ivy_FC489", "Ken_MC536", "Ray_MC729", "Roy_MC769" )

#subset movestack by cat names
subcats <- cats[[cat_list]]

#subset movestack by year
subcats <- subcats[year(timestamps(subcats))==2017] 

#subset movestack by months aug - nov
subcats <- subcats[month(timestamps(subcats))%in% c(8,9,10,11)]

#check timestamps
min(timestamps(subcats))
## [1] "2017-08-01 00:36:43 UTC"
max(timestamps(subcats))
## [1] "2017-11-30 23:00:37 UTC"
# align data to a uniform time scale, resample 4x daily
#reduces frames of movement animation to a resonable time
mC <- align_move(subcats, res = 6, unit = "hours")
## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html
## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

##Interactive location maps Before creating an animation, you can view all the location points for each individual on an interactive map, which allows you to zoom in/out and hover over each point to view information.

#colors for movement tracks
col = brewer.pal(n = 5, name = "Set2")

#create interactive map
view_spatial(mC, path_colours = col, render_as = "leaflet")

##Finally, animate the movement paths into a GIF

# create spatial frames with a basemap 
frames <- frames_spatial(mC, path_colours = col,
                         tail_colour = "white", tail_size = 0.8, #how to include tail
                         trace_show = TRUE, trace_colour = "darkgray", #how to include path trace
                         map_service = 'osm', map_type = "terrain",
                         alpha = 0.5) %>% 
  add_labels(x = "Longitude", y = "Latitude") %>% # add some customizations, such as axis labels
  add_northarrow() %>% 
  add_scalebar() %>% 
  add_timestamps(type = "label") %>% 
  add_progress()
## Checking temporal alignment...
## Processing movement data...
## Approximated animation duration: ˜ 19.36s at 25 fps for 484 frames
## Warning in CPL_crs_from_input(x): GDAL Message 1: +init=epsg:XXXX syntax is
## deprecated. It might return a CRS with a non-EPSG compliant axis order.
## Retrieving and compositing basemap imagery...
## Assigning raster maps to frames...
## Creating frames...
frames[[100]] # preview one of the frames, e.g. the 100th frame

animate_frames(frames, out_file = "catVis.gif", overwrite = TRUE)
## Rendering animation...
## Approximated animation duration: ˜ 19.36s at 25 fps for 484 frames

Movetrack visualization: foxes

We also created an interactive map of the fox locations and an animated path of the fox movement during the same time period as the cats.

Notice that with the moveVis package we are able to customize point and line colors, and map imagery.

## # A tibble: 9 x 2
##   local_identifier     n
##   <chr>            <int>
## 1 Don               5045
## 2 Ern               3908
## 3 Flo                717
## 4 Jen               3909
## 5 Joy               3150
## 6 Kev               4679
## 7 Lou               5269
## 8 Oli               4215
## 9 Ros               3963
## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html

## Warning in FUN(X[[i]], ...): CRS object has comment, which is lost in output; in tests, see
## https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html
## Checking temporal alignment...
## Processing movement data...
## Approximated animation duration: ˜ 17.96s at 25 fps for 449 frames
## Retrieving and compositing basemap imagery...
## Assigning raster maps to frames...
## Creating frames...
## Rendering animation...
## Approximated animation duration: ˜ 17.96s at 25 fps for 449 frames
## Warning in dir.create(frames_dir, recursive = T): 'C:
## \Users\veron\AppData\Local\Temp\RtmpEBa9Id\moveVis\frames' already exists

Lessons Learned

The moveVis package works exclusively with objects of class ‘movestack.’ While the package is supposed to allow easy conversion from a data frame to a movestack object, we were not able to successfully make this conversion within moveVis. We resorted to downloading the data directly from Movebank, which requires creating an account and accepting data use terms on the website first. This is not to say converting from a data frame is impossible, but this could make it more difficult for people to use moveVis if they are not housing their GPS data on Movebank.

There are large differences in processing time of the animated map depending on the frequency of location fixes. For example, 2 years of data at 20 minute fixes took several orders of magnitude longer (2 hours) to process than 6 months of data at 6 hour fixes (5 minutes).

Overall, it was quick to get started with the moveVis package, and fairly easy to get a basic map or gif created.

Other Visualization Tools

We investigated several other interactive mapping tools.

Leaflet and Mapview are utilized by the moveVis package, so the interactive maps created within moveVis are technically Leaflet maps. However, it is possible to customize interactive maps using Leaflet or Mapview directly. The customization process is very similar to ggplot2, and there are plentiful helpful resources online (https://rstudio.github.io/leaflet/).

Plotly is a commonly used package to upgrade a traditional ggplot to an interactive plot. This can be used for non-spatial data, too!

A package called DynamoVIS (https://dynamovis.geog.ucsb.edu/index) serves a similar purpose as moveVis, but it is not housed on CRAN and it must be downloaded from GitHub. The capabilities appear to be greater than moveVis, but it likely requires more effort from the user.

Next Steps

There were several customizations and visual integrations we hoped to accomplish with moveVis, but were not able to complete. 1. We attempted to set the path (“tail”) colors equal to the animated line, unique to each individual. It seems the package only allows a single parameter value for the tail color, but this is something we could explore further. 2. There is a function in moveVis that allows animated maps to play side-by-side, which would create a useful visualization. There are some underlying steps to align the maps properly, and we simply ran out of time to attempt this mapping feature. 3. Similarly, we wanted to combine the fox and cat movement paths into a single animated map, grouped by species. We encountered difficulties with this goal because the movestack data class can be difficult to manipulate. We have not determined if combining the data sets for a single animated map is impossible in the moveVis package, but we were not able to complete our attempt.